home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / math / ast53src.zip / IO.C < prev    next >
C/C++ Source or Header  |  1996-09-29  |  24KB  |  716 lines

  1. /*
  2. ** Astrolog (Version 5.30) File: io.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1996 by Walter D. Pullen
  6. ** (Astara@msn.com, http://www.magitech.com/~cruiser1/astrolog.htm).
  7. ** Permission is granted to freely use and distribute these routines
  8. ** provided one doesn't sell, restrict, or profit from them in any way.
  9. ** Modification is allowed provided these notices remain with any
  10. ** altered or edited versions of the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 9/22/1996.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. /*
  42. ******************************************************************************
  43. ** File IO Routines.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Open the file indicated by the given string and return the file's stream */
  48. /* pointer, or NULL if the file couldn't be found or opened. All parts of   */
  49. /* the program which open files to read call this routine. We look in       */
  50. /* several various locations and directories for the file before giving up. */
  51.  
  52. FILE *FileOpen(szFile, nFileMode)
  53. char *szFile;
  54. int nFileMode;
  55. {
  56.   FILE *file;
  57.   char name[cchSzDef], mode[3];
  58. #ifdef ENVIRON
  59.   char *env;
  60. #endif
  61.  
  62.   /* Some file types we want to open as binary instead of Ascii. */
  63.   sprintf(mode, "r%s", nFileMode == 2 ? "b" : "");
  64.  
  65.   /* First look for the file in the current directory. */
  66.   file = fopen(szFile, mode);
  67.   if (file != NULL)
  68.     return file;
  69.  
  70. #ifdef ENVIRON
  71.   /* Next look for the file in the directory indicated by the version */
  72.   /* specific system environment variable.                            */
  73.   sprintf(name, "%s%s", ENVIRONVER, szVersionCore);
  74.   env = getenv(name);
  75.   if (env && *env) {
  76.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  77.     file = fopen(name, mode);
  78.     if (file != NULL)
  79.       return file;
  80.   }
  81.  
  82.   /* Next look in the directory in the general environment variable. */
  83.   env = getenv(ENVIRONALL);
  84.   if (env && *env) {
  85.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  86.     file = fopen(name, mode);
  87.     if (file != NULL)
  88.       return file;
  89.   }
  90.  
  91.   /* Next look in the directory in the version prefix environment variable. */
  92.   env = getenv(ENVIRONVER);
  93.   if (env && *env) {
  94.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  95.     file = fopen(name, mode);
  96.     if (file != NULL)
  97.       return file;
  98.   }
  99. #endif
  100.  
  101.   /* Finally look in one of several directories specified at compile time. */
  102.   sprintf(name, "%s%c%s", nFileMode == 0 ? DEFAULT_DIR :
  103.     (nFileMode == 1 ? CHART_DIR : EPHE_DIR), chDirSep, szFile);
  104.   file = fopen(name, mode);
  105.   if (file == NULL && nFileMode == 1) {
  106.     /* If the file was never found, print an error (unless we were looking */
  107.     /* for a certain file type, e.g. the optional astrolog.dat file).      */
  108.     sprintf(name, "File '%s' not found.", szFile);
  109.     PrintError(name);
  110.   }
  111.   return file;
  112. }
  113.  
  114.  
  115. /* This is Astrolog's generic file processing routine, which handles chart */
  116. /* info files, position files, and config files. Given a file name or a    */
  117. /* file handle, run through each line as a series of command switches.     */
  118.  
  119. bool FProcessSwitchFile(szFile, file)
  120. char *szFile;
  121. FILE *file;
  122. {
  123.   char szLine[cchSzMax], *argv[MAXSWITCHES], ch;
  124.   int argc, i;
  125.  
  126.   if (file == NULL)
  127.     file = FileOpen(szFile, 0);
  128.   if (file == NULL)
  129.     return fFalse;
  130.  
  131.   /* All files have to begin with the -@ switch file type identifier. */
  132.   ch = getc(file); ungetc(ch, file);
  133.   if (ch != '@') {
  134.     sprintf(szLine,
  135.       "The command file '%s' is not in any valid format (character %d).",
  136.       szFile, (int)ch);
  137.     PrintWarning(szLine);
  138.     return fFalse;
  139.   }
  140.  
  141.   loop {
  142.     while (!feof(file) && (ch = getc(file)) < ' ')
  143.       ;
  144.     if (feof(file))
  145.       break;
  146.     for (szLine[0] = ch, i = 1; i < cchSzMax && !feof(file) &&
  147.       (szLine[i] = getc(file)) >= ' '; i++)
  148.       ;
  149.     szLine[i] = chNull;
  150.     argc = NParseCommandLine(szLine, argv);
  151.     if (!FProcessSwitches(argc, argv))
  152.       return fFalse;
  153.   }
  154.   return fTrue;
  155. }
  156.  
  157.  
  158. /* Take the current chart information, and write it out to the file   */
  159. /* as indicated by the -o switch. This is only executed at the end of */
  160. /* program execution if the -o switch is in effect.                   */
  161.  
  162. bool FOutputData()
  163. {
  164.   char sz[cchSzDef];
  165.   FILE *file;
  166.   int i, j;
  167.   real rT;
  168.  
  169.   if (us.fNoWrite)
  170.     return fFalse;
  171.   file = fopen(is.szFileOut, "w");  /* Create and open the file for output. */
  172.   if (file == NULL) {
  173.     sprintf(sz, "File %s can not be created.", is.szFileOut);
  174.     PrintError(sz);
  175.     return fFalse;
  176.   }
  177.   if (!us.fWritePos) {
  178.  
  179.     /* Write the chart information to the file. */
  180.  
  181.     if (Mon < 1) {
  182.       fclose(file);
  183.       PrintError("Can't output chart with no time/space to file.");
  184.       return fFalse;
  185.     }
  186.     if (us.fWriteOld) {
  187.       fprintf(file, "%d\n%d\n%d\n%.2f\n%.2f\n%.2f\n%.2f\n",
  188.         Mon, Day, Yea, Tim, Zon-Dst, Lon, Lat);
  189.     } else {
  190.       fprintf(file, "@0102  ; %s chart info.\n", szAppName);
  191.       i = us.fAnsiChar;
  192.       us.fAnsiChar = fFalse;
  193.       fprintf(file, "%cqb %c%c%c %d %d %s %s %s %s\n", chSwitch, chMon3(Mon),
  194.         Day, Yea, SzTim(Tim), Dst == 0.0 ? "ST" : (Dst == 1.0 ? "DT" :
  195.         SzZone(Dst)), SzZone(-Zon), SzLocation(Lon, Lat));
  196.       fprintf(file, "%czi \"%s\" \"%s\"\n", chSwitch, ciMain.nam, ciMain.loc);
  197.       us.fAnsiChar = i;
  198.     }
  199.   } else {
  200.  
  201.     /* However, if the -o0 switch is in effect, then write the actual */
  202.     /* positions of the planets and houses to the file instead.       */
  203.  
  204.     if (us.fWriteOld) {
  205.       for (i = 1; i <= oNorm; i++) {
  206.         j = (int)planet[i];
  207.         fprintf(file, "%c%c%c: %2d %2d %10.7f\n", chObj3(i),
  208.           j%30, j/30+1, RFract(planet[i])*60.0);              /* Position */
  209.         rT = planetalt[i];
  210.         fprintf(file, "[%c]: %3d %12.8f\n",                   /* Altitude */
  211.           ret[i] >= 0.0 ? 'D' : chRet, (int)(RSgn(rT)*
  212.           RFloor(RAbs(rT))), (rT-(real)(int)rT)*60.0);     /* Retrograde? */
  213.         if (i == oNod)
  214.           i = oFor-1;
  215.         else if (i == oFor)
  216.           i = oMC -1;
  217.         else if (i == oMC)
  218.           i = oAsc-1;
  219.         else if (i == oAsc)
  220.           i = oVtx-1;
  221.         else if (i == oVtx)    /* Skip minor cusps to write uranians  */
  222.           i = us.fUranian ? uranLo-1 : cObj;
  223.       }
  224.       for (i = 1; i <= cSign/2; i++) {   /* Write first six cusp positions */
  225.         j = (int)chouse[i];
  226.         fprintf(file, "H_%c: %2d %2d %10.7f\n",
  227.           'a'+i-1, j%30, j/30+1, RFract(chouse[i])*60.0);
  228.       }
  229.  
  230.     } else {
  231.       fprintf(file, "@0203  ; %s chart positions.\n", szAppName);
  232.       fprintf(file, "%czi \"%s\" \"%s\"\n", chSwitch, ciMain.nam, ciMain.loc);
  233.       for (i = 1; i <= cObj; i++) if (!ignore[i] || FCusp(i)) {
  234.         fprintf(file, "%cYF ", chSwitch);
  235.         if (i <= oNorm)
  236.           fprintf(file, "%c%c%c", chObj3(i));
  237.         else
  238.           fprintf(file, "%3d", i);
  239.         rT = FBetween(i, cuspLo-1+4, cuspLo-1+9) ?
  240.           chouse[i-(cuspLo-1)] : planet[i];
  241.         j = (int)rT;
  242.         fprintf(file, ":%3d %c%c%c%13.9f,%4d%13.9f,",
  243.           j%30, chSig3(j/30+1), RFract(rT)*60.0,
  244.           (int)planetalt[i], RFract(RAbs(planetalt[i]))*60.0);
  245.         rT = i > oNorm ? 999.0 : (i == oMoo && !us.fPlacalc ? 0.0026 :
  246.           RSqr(spacex[i]*spacex[i]+spacey[i]*spacey[i]+spacez[i]*spacez[i]));
  247.         fprintf(file, "%14.9f%14.9f\n", DFromR(ret[i]), rT);
  248.       }
  249.     }
  250.   }
  251.  
  252.   /* Now write any extra strings that were on the command line after the -o */
  253.   /* specification but before the next switch, to the file as comments.     */
  254.  
  255.   for (i = 1; i < is.cszComment; i++) {
  256.     is.rgszComment++;
  257.     fprintf(file, "%s%s\n", us.fWriteOld ? "" : "; ", is.rgszComment[1]);
  258.   }
  259.   fclose(file);
  260.   return fTrue;
  261. }
  262.  
  263.  
  264. /*
  265. ******************************************************************************
  266. ** User Input Routines.
  267. ******************************************************************************
  268. */
  269.  
  270. /* Given a string, return an index number corresponding to what the string */
  271. /* indicates, based on a given parsing mode. In most cases this is mainly  */
  272. /* looking up a string in the appropriate array and returning the index.   */
  273.  
  274. int NParseSz(szEntry, pm)
  275. char *szEntry;
  276. int pm;
  277. {
  278.   char szLocal[cchSzMax], *sz, ch0, ch1, ch2;
  279.   int cch, n, i;
  280.  
  281.   /* First strip off any leading or trailing spaces. */
  282.   for (cch = 0; szLocal[cch] = szEntry[cch]; cch++)
  283.     ;
  284.   while (cch && szLocal[cch-1] <= ' ')
  285.     szLocal[--cch] = chNull;
  286.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--)
  287.     ;
  288.  
  289.   if (cch >= 3) {
  290.     ch0 = ChCap(sz[0]); ch1 = ChUncap(sz[1]); ch2 = ChUncap(sz[2]);
  291.     switch (pm) {
  292.     /* Parse months, e.g. "February" or "Feb" -> 2 for February. */
  293.     case pmMon:
  294.       for (i = 1; i <= cSign; i++) {
  295.         if (ch0 == szMonth[i][0] && ch1 == szMonth[i][1] &&
  296.           ch2 == szMonth[i][2])
  297.           return i;
  298.       }
  299.       break;
  300.     /* Parse planets, e.g. "Jupiter" or "Jup" -> 6 for Jupiter. */
  301.     case pmObject:
  302.       for (i = 1; i <= cObj; i++) {
  303.         if (ch0 == szObjName[i][0] && ch1 == szObjName[i][1] &&
  304.           ch2 == szObjName[i][2])
  305.           return i;
  306.       }
  307.       if (ch0 == 'L' && ch1 == 'i' && ch2 == 'l')
  308.         return oLil;
  309.       if (ch0 == 'S' && ch1 == '.' && ch2 == 'n')
  310.         return oSou;
  311.       break;
  312.     /* Parse aspects, e.g. "Conjunct" or "Con" -> 1 for the Conjunction. */
  313.     case pmAspect:
  314.       for (i = 1; i <= cAspect; i++) {
  315.         if (ch0 == szAspectAbbrev[i][0] &&
  316.           ch1 == ChUncap(szAspectAbbrev[i][1]) &&
  317.           ch2 == szAspectAbbrev[i][2])
  318.           return i;
  319.       }
  320.       break;
  321.     /* Parse house systems, e.g. "Koch" or "Koc" -> 1 for Koch houses. */
  322.     case pmSystem:
  323.       for (i = 1; i <= cSystem; i++) {
  324.         if (ch0 == szSystem[i][0] && ch1 == szSystem[i][1] &&
  325.           ch2 == szSystem[i][2])
  326.           return i;
  327.       }
  328.     /* Parse zodiac signs, e.g. "Scorpio" or "Sco" -> 8 for Scorpio. */
  329.     case pmSign:
  330.       for (i = 1; i <= cSign; i++) {
  331.         if (ch0 == szSignName[i][0] && ch1 == szSignName[i][1] &&
  332.           ch2 == szSignName[i][2])
  333.           return i;
  334.       }
  335.     /* Parse colors, e.g. "White" or "Whi" -> 15 for White. */
  336.     case pmColor:
  337.       for (i = 0; i < 16 ; i++) {
  338.         if (ch0 == szColor[i][0] && ch1 == szColor[i][1] &&
  339.           ch2 == ChUncap(szColor[i][2]))
  340.           return i;
  341.       }
  342.     }
  343.   }
  344.   n = atoi(sz);
  345.  
  346.   if (pm == pmYea) {
  347.     /* For years, process any "BC" (or "B.C.", "b.c", and variations) and   */
  348.     /* convert an example such as "5BC" to -4. For negative years, note the */
  349.     /* difference of one, as 1AD was preceeded by 1BC, with no year zero.   */
  350.     i = Max(cch-1, 0);
  351.     if (i && sz[i] == '.')
  352.       i--;
  353.     if (i && ChCap(sz[i]) == 'C')
  354.       i--;
  355.     if (i && sz[i] == '.')
  356.       i--;
  357.     if (i && ChCap(sz[i]) == 'B')
  358.       n = 1 - n;
  359.   }
  360.   return n;
  361. }
  362.  
  363.  
  364. /* Given a string, return a floating point number corresponding to what the  */
  365. /* string indicates, based on a given parsing mode, like above for integers. */
  366.  
  367. real RParseSz(szEntry, pm)
  368. char *szEntry;
  369. int pm;
  370. {
  371.   char szLocal[cchSzMax], *sz, *pch, ch;
  372.   int cch, i, f = fFalse;
  373.   real r;
  374.  
  375.   /* First strip off any leading or trailing spaces. */
  376.   for (cch = 0; szLocal[cch] = szEntry[cch]; cch++)
  377.     ;
  378.   while (cch && szLocal[cch-1] <= ' ')
  379.     szLocal[--cch] = chNull;
  380.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--);
  381.     ;
  382.   /* Capitalize all letters and make colons be periods to be like numbers. */
  383.   for (pch = sz; *pch; pch++) {
  384.     ch = *pch;
  385.     if (ch == ':')
  386.       ch = '.';
  387.     else
  388.       ch = ChCap(ch);
  389.     *pch = ch;
  390.   }
  391.   ch = sz[0];
  392.  
  393.   if (pm == pmTim) {
  394.     /* For times, process "Noon" and "Midnight" (or just "N" and "M"). */
  395.     if (ch == 'N')
  396.       return 12.0;
  397.     else if (ch == 'M')
  398.       return 0.0;
  399.   } else if (pm == pmDst) {
  400.     /* For the Daylight time flag, "Daylight", "Yes", and "True" (or just */
  401.     /* their first characters) are all indications to be ahead one hour.  */
  402.     if (ch == 'D' || ch == 'Y' || ch == 'T')
  403.       return 1.0;
  404.     /* "Standard", "No", and "False" mean the normal zero offset. */
  405.     else if (ch == 'S' || ch == 'N' || ch == 'F')
  406.       return 0.0;
  407.   } else if (pm == pmZon) {
  408.     /* For time zones, see if the abbrev is in a table, e.g. "EST" -> 5. */
  409.     for (i = 0; i < cZone; i++)
  410.       if (NCompareSz(sz, szZon[i]) == 0)
  411.         return rZon[i];
  412.   } else if (pm == pmLon || pm == pmLat) {
  413.     /* For locations, negate the value for an "E" or "S" in the middle    */
  414.     /* somewhere (e.g. "105E30" or "27:40S") for eastern/southern values. */
  415.     for (i = 0; i < cch; i++) {
  416.       ch = sz[i];
  417.       if (FCapCh(ch)) {
  418.         if (ch == 'E' || ch == 'S')
  419.           f = fTrue;
  420.         sz[i] = '.';
  421.         i = cch;
  422.       }
  423.     }
  424.     ch = sz[0];
  425.   }
  426.  
  427.   /* Anything still at this point should be in a numeric format. */
  428.   if (!FNumCh(ch) && ch != '+' && ch != '-' && ch != '.')
  429.     return rLarge;
  430.   r = (f ? -1.0 : 1.0) * atof(sz);
  431.  
  432.   if (pm == pmTim) {
  433.     /* Backtrack over any time suffix, e.g. "AM", "p.m." and variations. */
  434.     i = Max(cch-1, 0);
  435.     if (i && sz[i] == '.')
  436.       i--;
  437.     if (i && sz[i] == 'M')
  438.       i--;
  439.     if (i && sz[i] == '.')
  440.       i--;
  441.     if (i) {
  442.       ch = sz[i];
  443.       if (ch == 'A')                   /* Adjust value appropriately */
  444.         r = r >= 12.0 ? r-12.0 : r;    /* if AM or PM suffix.        */
  445.       else if (ch == 'P')
  446.         r = r >= 12.0 ? r : r+12.0;
  447.     }
  448.   }
  449.   return r;
  450. }
  451.  
  452.  
  453. /* Stop and wait for the user to enter a line of text given a prompt to */
  454. /* display and a string buffer to fill with it.                         */
  455.  
  456. void InputString(szPrompt, sz)
  457. char *szPrompt, *sz;
  458. {
  459.   FILE *file;
  460.   int cch;
  461.  
  462.   file = is.S; is.S = stdout;
  463.   PrintSz(szPrompt);
  464.   AnsiColor(kYellow);
  465.   PrintSz(" > ");
  466.   AnsiColor(kDefault);
  467.   if (fgets(sz, cchSzMax, stdin) == NULL)  /* Pressing control-D terminates */
  468.     Terminate(tcForce);                    /* the program on some machines. */
  469.   cch = CchSz(sz);
  470.   while (cch > 0 && sz[cch-1] < ' ')
  471.     cch--;
  472.   sz[cch] = chNull;
  473.   is.S = file;
  474.   is.cchCol = 0;
  475. }
  476.  
  477.  
  478. /* Prompt the user for a floating point value, parsing as appropriate, and */
  479. /* make sure it conforms to the specified bounds before returning it.      */
  480.  
  481. int NInputRange(szPrompt, low, high, pm)
  482. char *szPrompt;
  483. int low, high;
  484. int pm;
  485. {
  486.   char szLine[cchSzDef];
  487.   int n;
  488.  
  489.   loop {
  490.     InputString(szPrompt, szLine);
  491.     n = NParseSz(szLine, pm);
  492.     if (FBetween(n, low, high))
  493.       return n;
  494.     sprintf(szLine, "Value %d out of range from %d to %d.", n, low, high);
  495.     PrintWarning(szLine);
  496.   }
  497. }
  498.  
  499.  
  500. /* This is identical to above except it takes/returns floating point values. */
  501.  
  502. real RInputRange(szPrompt, low, high, pm)
  503. char *szPrompt;
  504. real low, high;
  505. int pm;
  506. {
  507.   char szLine[cchSzDef];
  508.   real r;
  509.  
  510.   loop {
  511.     InputString(szPrompt, szLine);
  512.     r = RParseSz(szLine, pm);
  513.     if (FBetween(r, low, high))
  514.       return r;
  515.     sprintf(szLine, "Value %.0f out of range from %.0f to %.0f.",
  516.       r, low, high);
  517.     PrintWarning(szLine);
  518.   }
  519. }
  520.  
  521.  
  522. /* This important procedure gets all the parameters defining the chart that  */
  523. /* will be worked with later. Given a "filename", it gets from it all the    */
  524. /* pertinent chart information. This is more than just reading from a file - */
  525. /* the procedure also takes care of the cases of prompting the user for the  */
  526. /* information and using the time functions to determine the date now - the  */
  527. /* program considers these cases "virtual" files. Furthermore, when reading  */
  528. /* from a real file, we have to check if it was written in the -o0 format.   */
  529.  
  530. bool FInputData(szFile)
  531. char *szFile;
  532. {
  533.   FILE *file;
  534.   char sz[cchSzDef], ch;
  535.   int i, fT;
  536.   real k, l, m;
  537.  
  538.   /* If we are to read from the virtual file "nul" that means to leave the */
  539.   /* chart information alone with whatever settings it may have already.   */
  540.  
  541.   if (NCompareSz(szFile, szNulCore) == 0) {
  542.     is.fHaveInfo = fTrue;
  543.     return fTrue;
  544.   }
  545.  
  546.   /* If we are to read from the virtual file "set" then that means use a   */
  547.   /* particular set of chart information generated earlier in the program. */
  548.  
  549.   if (NCompareSz(szFile, szSetCore) == 0) {
  550.     is.fHaveInfo = fTrue;
  551.     ciCore = ciSave;
  552.     return fTrue;
  553.   }
  554.  
  555. #ifdef TIME
  556.   /* If we are to read from the file "now" then that means use the time */
  557.   /* functions to calculate the present date and time.                  */
  558.  
  559.   if (NCompareSz(szFile, szNowCore) == 0) {
  560.     is.fHaveInfo = fTrue;
  561.     SS = us.dstDef; ZZ = us.zonDef; OO = us.lonDef; AA = us.latDef;
  562.     GetTimeNow(&MM, &DD, &YY, &TT, ZZ-SS);
  563.     ciCore.nam = ciCore.loc = "";
  564.     return fTrue;
  565.   }
  566. #endif
  567.  
  568. #ifndef WIN
  569.   /* If we are to read from the file "tty" then that means prompt the user */
  570.   /* for all the chart information.                                        */
  571.  
  572.   if (NCompareSz(szFile, szTtyCore) == 0) {
  573.     file = is.S; is.S = stdout;
  574.     if (!us.fNoSwitches) {
  575.       /* Temporarily disable an internal redirection of output to a file  */
  576.       /* because we always want user headers and prompts to be displayed. */
  577.  
  578.       AnsiColor(kWhite);
  579.       sprintf(sz, "** %s version %s ", szAppName, szVersionCore); PrintSz(sz);
  580.       sprintf(sz, "(See '%cHc' switch for copyrights and credits.) **\n",
  581.         chSwitch); PrintSz(sz);
  582.       AnsiColor(kDefault);
  583.       sprintf(sz, "   Invoke as '%s %cH' for list of command line options.\n",
  584.         ProcessProgname(is.szProgName), chSwitch); PrintSz(sz);
  585.     }
  586.  
  587.     MM = NInputRange("Enter month for chart (e.g. '8' 'Aug')",
  588.       1, 12, pmMon);
  589.     DD = NInputRange("Enter day   for chart (e.g. '1' '31') ",
  590.       1, DayInMonth(MM, 0), pmDay);
  591.     YY = NInputRange("Enter year  for chart (e.g. '1995')   ",
  592.       -5000, 5000, pmYea);
  593.     if (FBetween(YY, 0, 99)) {
  594.       sprintf(sz,
  595.         "Assuming first century A.D. is really meant instead of %d.",
  596.         1900 + YY);
  597.       PrintWarning(sz);
  598.     }
  599.     TT = RInputRange("Enter time  for chart (e.g. '18:30' '6:30pm')  ",
  600.       -2.0, 24.0, pmTim);
  601.     SS = us.fWriteOld ? 0.0 :
  602.       RInputRange("Enter if Daylight time in effect (e.g. 'y' '1')",
  603.       -24.0, 24.0, pmDst);
  604.     ZZ = RInputRange("Enter time zone (e.g. '5' 'ET' for Eastern)    ",
  605.       -24.0, 24.0, pmZon);
  606.     if ((int)(RFract(ZZ) * 100.0 + rRound) == 50) {
  607.       PrintWarning(
  608.         "Assuming unusual zone of 50 minutes after the hour instead of 30.");
  609.     }
  610.     OO = RInputRange("Enter Longitude of place (e.g. '122W20')",
  611.       -rDegHalf, rDegHalf, pmLon);
  612.     AA = RInputRange("Enter Latitude  of place (e.g. '47N36') ",
  613.       -rDegQuad, rDegQuad, pmLat);
  614.     if (!us.fWriteOld) {
  615.       InputString("Enter name or title for chart ", sz);
  616.       ciCore.nam = SzPersist(sz);
  617.       InputString("Enter name of city or location", sz);
  618.       ciCore.loc = SzPersist(sz);
  619.     }
  620.     PrintL();
  621.     is.cchRow = 0;
  622.     is.S = file;
  623.     return fTrue;
  624.   }
  625. #endif /* WIN */
  626.  
  627.   /* Now that the special cases are taken care of, we can assume we are */
  628.   /* to read from a real file.                                          */
  629.  
  630.   file = FileOpen(szFile, 1);
  631.   if (file == NULL)
  632.     return fFalse;
  633.   is.fHaveInfo = fTrue;
  634.   ch = getc(file); ungetc(ch, file);
  635.  
  636.   /* Read the chart parameters from a standard command switch file. */
  637.  
  638.   if (ch == '@') {
  639.     fT = is.fSzPersist; is.fSzPersist = fFalse;
  640.     if (!FProcessSwitchFile(szFile, file))
  641.       return fFalse;
  642.     is.fSzPersist = fT;
  643.  
  644.   /* Read the chart info from an older style -o list of seven numbers. */
  645.  
  646.   } else if (FNumCh(ch)) {
  647.     SS = 0.0;
  648.     fscanf(file, "%d%d%d", &MM, &DD, &YY);
  649.     fscanf(file, "%lf%lf%lf%lf", &TT, &ZZ, &OO, &AA);
  650.     if (!FValidMon(MM) || !FValidDay(DD, MM, YY) || !FValidYea(YY) ||
  651.       !FValidTim(TT) || !FValidZon(ZZ) || !FValidLon(OO) || !FValidLat(AA)) {
  652.       PrintWarning("Values in old style chart info file are out of range.");
  653.       return fFalse;
  654.     }
  655.  
  656.   /* Read the actual chart positions from a file produced with the -o0. */
  657.  
  658.   } else if (ch == 'S') {
  659.     MM = -1;
  660.  
  661.     /* Hack: A negative month value means the chart parameters are invalid, */
  662.     /* hence -o0 is in effect and we can assume the chart positions are     */
  663.     /* already in memory so we don't have to calculate them later.          */
  664.  
  665.     for (i = 1; i <= oNorm; i++) {
  666.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  667.       planet[i] = Mod((l-1.0)*30.0+k+m/60.0);
  668.       fscanf(file, "%s%lf%lf", sz, &k, &l);
  669.       if ((m = k+l/60.0) > rDegHalf)
  670.         m = rDegMax - m;
  671.       planetalt[i] = m;
  672.       ret[i] = RFromD(sz[1] == 'D' ? 1.0 : -1.0);
  673.  
  674.       /* -o0 files from versions 3.05 and before don't have the uranians in  */
  675.       /* them. Be prepared to skip over them in old files for compatibility. */
  676.  
  677.       if (i == oVtx) {
  678.         while (getc(file) >= ' ')
  679.           ;
  680.         if ((ch = getc(file)) != 'H')
  681.           i = cuspHi;
  682.         else
  683.           i = cObj;
  684.       }
  685.       if (i == oNod)
  686.         i = oFor-1;
  687.       else if (i == oFor)
  688.         i = oLil-1;
  689.       else if (i == oLil)
  690.         i = oEP -1;
  691.       else if (i == oEP)
  692.         i = oVtx-1;
  693.     }
  694.     for (i = 1; i <= cSign/2; i++) {
  695.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  696.       chouse[i+6] = Mod((chouse[i] = Mod((l-1.0)*30.0+k+m/60.0))+rDegHalf);
  697.     }
  698.     for (i = 1; i <= cSign; i++)
  699.       planet[cuspLo-1+i] = chouse[i];
  700.     planet[oMC] = planet[oLil]; planet[oNad] = Mod(planet[oMC]  + rDegHalf);
  701.     planet[oAsc] = planet[oEP]; planet[oDes] = Mod(planet[oAsc] + rDegHalf);
  702.     planet[oSou] = Mod(planet[oNod] + rDegHalf); ret[oSou] = ret[oNod];
  703.  
  704.   } else {
  705.     sprintf(sz,
  706.       "The chart info file is not in any valid format (character %d).",
  707.       (int)ch);
  708.     PrintWarning(sz);
  709.     return fFalse;
  710.   }
  711.   fclose(file);
  712.   return fTrue;
  713. }
  714.  
  715. /* io.c */
  716.